<?php

    /**
    * Mukei Development Framework
    *
    * Mukei is a development framework system created to provide developers
    * two main features: a plugin architecture which and expand the
    * functionality of the system and an event system which allows exansion of
    * existing plugins without modifing the original code.  The Mukei
    * development framework system can speed up development of new web
    * applications and reduce maintenance time of existing code.
    *
    * This file is part of Mukei.
    *
    * Mukei is free software; you can redistribute it and/or modify it under
    * the terms of the GNU General Public License as published by the Free
    * Software Foundation; either version 3 of the License, or (at your option)
    * any later version.
    *
    * Mukei is distributed in the hope that it will be useful, but WITHOUT ANY
    * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    * details.
    *
    * You should have received a copy of the GNU General Public License
    * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    *
    * @package   Mukei
    * @version   0.2
    * @author    Kevin Herrera
    * @license   http://www.gnu.org/licenses/gpl.txt GNU GPL v3
    * @copyright Copyright (c) 2007 Kevin Herrera.
    */

    /**
    * Admin System Plugin
    *
    * This system plugin provides the system the ability to manage plugins,
    * settings, and other functions that are expanded upon by each plugin.
    * To access the administrative panel, the field value of "act" must have
    * the value of "Admin" (/act,Admin/ or ?act=Admin).  From there you will
    * be able to select which plugin to manage.  Only plugins that contain
    * the ADMIN class constant, and the constant value must be the boolean
    * value of true, will be show in the list.  The ADMIN class constant
    * indicuates that the plugin supports administrative access.
    *
    * For a plugin to properly display the administrative pages, the plugin
    * must use the methods in this class to generate its output.  Deviation
    * from this rule may result in corrupted ouput and/or corrupted input.
    * Developers for system plugin admins classes also should not rely on the
    * "act" field.  During administrative mode, this field is reserved for
    * this system plugin.  Alterations to the value of this field will result
    * in the administrative mode being disabled and/or unexepcted results from
    * a different plugin.
    *
    * @package Admin
    * @version 0.2
    * @final
    */
    final class Admin
    {
        /**#@+
        * @access public
        * @var    const
        */
        const ACTION   = "Admin";
        const ADMIN    = true;
        const AUTHOR   = "Kevin Herrera";
        const DESC     = "Administrative control system for Mukei.";
        const HANDLE   = "ADM";
        const METHOD   = "_action";
        const NAME     = "Mukei Admin System";
        const REQUIRED = "0.2";
        const VERSION  = "0.2";
        /**#@-*/

        /**#@+
        * @access private
        * @var    array
        */
        private $_left    = array( );
        private $_modules = array( );
        private $_panels  = array( );
        private $_right   = array( );
        /**#@-*/

        /**
        * Class Constructor
        *
        * This system method reports to the system what this system plugins
        * dependencies are.  Alterations to this list is not suggested.  If
        * additional dependencies are required by the a plugin loaded in
        * administrative mode, that plugin should report its dependencies to
        * the system (Mukei).  This method also declares page type constants
        * that should be used with the page_info() method and administrative
        * level constants.  The administrative constant, M_ADMIN_LEVEL_1, will
        * always be the highest level of authority in the system.
        *
        * @access public
        * @see    Admin::page_info()
        * @uses   m_define()
        * @uses   Mukei::depend()
        * @return object
        */
        public function __construct ( )
        {
            // Get global.
            global $M;

            // Add dependencies.
            $M->depend( array(

                'BRW'   => "Browser",
                'CLI'   => "Client",
                'MEM'   => "Members",
                'TPL'   => "Template",

            ) );

            // Define system constants.
            if ( !m_define( 'M_ADMIN_CLIENT', "clients" ) ||
                 !m_define( 'M_ADMIN_EVENT',  "events"  ) ||
                 !m_define( 'M_ADMIN_HOME',   "home"    ) ||
                 !m_define( 'M_ADMIN_OTHER',  "other"   ) ||
                 !m_define( 'M_ADMIN_SYSTEM', "systems" ) )
            {
                // Report fatal error.
                trigger_error( "Unable to define admin system constants.",
                               E_USER_ERROR );
            }

            // Number auth levels.
            $levels = 10;

            // Define auth level constants.
            for ( $index = 1; $index <= $levels; $index++ )
            {
                // Define constant.
                if ( !m_define( "M_ADMIN_LEVEL_${index}",
                                "level_{$index}" ) )
                {
                    // Report fatal error.
                    trigger_error( "Unable to define admin level constant.",
                                   E_USER_ERROR );
                }
            }
        }

        /**
        * Client Action
        *
        * This system method executes the appropriate administrative class for
        * the specified plugin.  If no plugin was specified, specified plugin
        * contains invalid characters, does not support admin mode, or the
        * plugin class does not exist, the default administrative class will be
        * executed, Admin_Admin.  If the specified plugin does exist and does
        * support admin mode but its administrative class is missing, a fatal
        * error will be triggered.  After all checks are passed, the
        * Smarty template engine will be reconfigured and the appropriate admin
        * class will be executed.
        *
        * @access public
        * @uses   m_define()
        * @uses   m_path()
        * @uses   Browser::update()
        * @uses   Browser::url()
        * @uses   Members::admin()
        * @uses   Members::denied()
        * @uses   Smarty::assign()
        * @return void
        */
        public function _action ( )
        {
            // Get global.
            global $M;

            // Is not admin?
            if( $M->MEM->admin( ) )
            {
                // Access denied.
                $M->MEM->denied( );

                // Stop.
                return;
            }

            // No sub action?
            if ( empty( $M->BRW->ALL['sub'] ) )
            {
                // Set default.
                $M->BRW->update( "sub", "Admin" );
            }

            // Sub action contains invalid characters?
            if ( !preg_match( "/^[a-zA-Z_]+$/", $M->BRW->_ALL['sub'] ) )
            {
                // Set default.
                $M->BRW->update( "sub", "Admin" );
            }

            // Class does not exist?
            if ( !class_exists( $M->BRW->ALL['sub'] ) )
            {
                // Set default.
                $M->BRW->update( "sub", "Admin" );
            }

            // Initialize vars.
            $class = "Admin_Admin";
            $value = false;

            // Class does not support admin mode?
            if ( !( $value = @constant( $M->BRW->ALL['sub'] . "::ADMIN" ) ) ||
                  ( $value !== true ) )
            {
                // Set default.
                $M->BRW->update( "sub", "Admin" );
            }

            // Admin mode supported?
            if ( $value === true )
            {
                // Set class.
                $class = $M->BRW->ALL['sub'] . "_Admin";

                // Class does not exist?
                if ( !class_exists( $class ) )
                {
                    // Report fatal error.
                    trigger_error( "Plugin, " . $M->BRW->ALL['sub'] . ", "   .
                                   "claims to support admin mode but admin " .
                                   "class, $class, does not exist.",
                                   E_USER_ERROR );
                }
            }

            // Declare default paths.
            m_define( 'M_ADMIN_TEMPLATE', M_TEMPLATES_DIR .
                                          "admin"         .
                                          M_SEP );
            m_define( 'M_ADMIN_CACHE',    M_TEMP_DIR      .
                                          "admin"         .
                                          M_SEP );

            // Check admin template directory.
            if ( !m_path( M_ADMIN_TEMPLATE,
                          M_DIRECTORY,
                          true ) )
            {
                // Report fatal error.
                trigger_error( "Administrative template directory, " .
                               M_ADMIN_TEMPLATE . ", has errors.",
                               E_USER_ERROR );
            }

            // Check admin cache directory.
            if ( !m_path( M_ADMIN_CACHE,
                          M_DIRECTORY,
                          true ) )
            {
                // Report fatal error.
                trigger_error( "Administrative cache directory, " .
                               M_ADMIN_CACHE . ", has errors.",
                               E_USER_ERROR );
            }

            // Reconfigure Smarty.
            $M->TPL->template_dir = M_ADMIN_TEMPLATE;
            $M->TPL->compile_dir  = M_ADMIN_CACHE;

            // List navigation.
            $nav = array(

                'home'      => "",
                'clients'   => "clients",
                'events'    => "events",
                'systems'   => "systems",
                'other'     => "other",

            );

            // Assign Smarty vars.
            $M->TPL->assign( "template_url",
                             M_TEMPLATES_URL .
                             "admin/" );
            $M->TPL->assign( "admin_url",
                             $M->BRW->url( array(

                                'act'   => "Admin",

                             ) ) );

            // Walk through navigation.
            foreach ( $nav as $name => $link )
            {
                // Create var name.
                $var = "admin_${name}_url";

                // Compose URL values.
                $values = array(

                    'act'   => "Admin",
                    'sub'   => "Admin",

                );

                // Have link?
                if ( !empty( $link ) )
                {
                    // Add.
                    $values['page'] = $link;
                }

                // Create var value.
                $value = $M->BRW->url( $values );

                // Assign Smarty var.
                $M->TPL->assign( $var, $value );
            }

            // Execute class.
            new $class ( );
        }

        /**
        * Add Sidebar Module
        *
        * This system method will add a sidebar module to the administrative
        * page that will be displayed when another system render() is called.
        * The value returned is the index of where the module is stored in the
        * array.  This index value is required for other system methods in
        * order to append content to the module or to remove it from the
        * final output.
        *
        * @access public
        * @uses   m_arg()
        * @param  string  $title    optional New module's title.
        * @param  string  $contents          Contents of new module.
        * @return integer
        */
        public function add_module ( $title = "",
                                     $contents )
        {
            // Check arguments.
            m_arg( $title,    M_STRING, false );
            m_arg( $contents, M_STRING        );

            // Append to list.
            array_push( $this->_modules, array(

                'title'     => $title,
                'contents'  => $contents,

            ) );

            // Move array cursor.
            end( $this->_modules );

            // Get index.
            $index = key( $this->_modules );

            // Reset cursor.
            reset( $this->_modules );

            return( $index );
        }

        /**
        * Append to Sidebar Module
        *
        * This system method appends the given contents to an existing sidebar
        * module.  If the module does not exist, a warning will be triggered
        * and the boolean value of false will be returned.  If the module does
        * exist, the content will be appended to the end of the module and the
        * boolean value of true will be returned.
        *
        * @access public
        * @uses   m_arg()
        * @param  integer $index    Existing module's index.
        * @param  string  $contents Contents to append to module with.
        * @return boolean
        */
        public function append_module ( $index,
                                        $contents )
        {
            // Check arguments.
            m_arg( $index,    M_INTEGER );
            m_arg( $contents, M_STRING  );

            // Valid index?
            if ( !empty( $this->_modules[ $index ] ) )
            {
                // Append contents.
                $this->_modules[ $index ]['content'] .= $contents;

                return( true );
            }

            // Invalid index?
            else
            {
                // Report warning.
                trigger_error( "Admin module index out of bounds: $index.",
                               E_USER_WARNING );
            }

            return( false );
        }

        /**
        * Add Content Panel
        *
        * This system method will add a contenet panel to the administrative
        * page that will be displayed when another system render() is called.
        * The value returned is the index of where the panel is stored in the
        * array.  This index value is required for other system methods in
        * order to append content to the panel or to remove it from the
        * final output.
        *
        * @access public
        * @uses   m_arg()
        * @param  string  $title    optional New panel's title.
        * @param  string  $contents          Contents of new panel.
        * @return integer
        */
        public function add_panel ( $title = "",
                                    $contents )
        {
            // Check arguments.
            m_arg( $title,    M_STRING, false );
            m_arg( $contents, M_STRING        );

            // Append to list.
            array_push( $this->_panels, array(

                'title'     => $title,
                'contents'  => $contents,

            ) );

            // Move array cursor.
            end( $this->_panels );

            // Get index.
            $index = key( $this->_panels );

            // Reset cursor.
            reset( $this->_panels );

            return( $index );
        }

        /**
        * Append to Content Panel
        *
        * This system method appends the given contents to an existing content
        * panel.  If the panel does not exist, a warning will be triggered
        * and the boolean value of false will be returned.  If the panel does
        * exist, the content will be appended to the end of the panel and the
        * boolean value of true will be returned.
        *
        * @access public
        * @uses   m_arg()
        * @param  integer $index    Existing panel's index.
        * @param  string  $contents Contents to append to panel with.
        * @return boolean
        */
        public function append_panel ( $index,
                                       $contents )
        {
            // Check arguments.
            m_arg( $index,    M_INTEGER );
            m_arg( $contents, M_STRING  );

            // Valid index?
            if ( !empty( $this->_panels[ $index ] ) )
            {
                // Append contents.
                $this->_panels[ $index ]['content'] .= $contents;

                return( true );
            }

            // Invalid index?
            else
            {
                // Report warning.
                trigger_error( "Admin panel index out of bounds: $index.",
                               E_USER_WARNING );
            }

            return( false );
        }

        /**
        * Create List
        *
        * This system method will attempt to create a list using the array
        * provided with the administrative template called "list.tpl".  If no
        * content is returned, the boolean value of false will be returned.
        * If content is returned, the string generated will be returned.  This
        * string may be used with the other system methods add/append_module()
        * and add/append_panel().
        *
        * @access public
        * @uses   m_arg()
        * @uses   Smarty::assign()
        * @uses   Smarty::fetch()
        * @param  array  $content Array of links and/or text.
        * @return string
        */
        public function create_list ( $content )
        {
            // Check argument.
            m_arg( $content, M_ARRAY );

            // Get global.
            global $M;

            // Assign temporary var.
            $M->TPL->assign( "admin_list_content",
                             $content );

            // Fetch contents.
            $contents = $M->TPL->fetch( "list.tpl" );

            // Contents not empty?
            if ( !empty( $contents ) )
            {
                // Return contents.
                return( $contents );
            }

            return( false );
        }

        /**
        * Create Paragraph
        *
        * This system method will attempt to create a paragraph using the
        * string provided with the administrative template called "para.tpl".
        * If no content is returned, the boolean value of false will be
        * returned. If content is returned, the string generated will be
        * returned.  This string may be used with the other system methods
        * add/append_module() and add/append_panel().
        *
        * @access public
        * @uses   m_arg()
        * @uses   Smarty::assign()
        * @uses   Smarty::fetch()
        * @param  string $content Paragraph contents.
        * @return string
        */
        public function create_para ( $content )
        {
            // Check argument.
            m_arg( $content, M_STRING );

            // Get global.
            global $M;

            // Assign temporary var.
            $M->TPL->assign( "admin_para_content",
                             $content );

            // Fetch contents.
            $contents = $M->TPL->fetch( "para.tpl" );

            // Contents not empty?
            if ( !empty( $contents ) )
            {
                // Return contents.
                return( $contents );
            }

            return( false );
        }

        /**
        * Create Heading
        *
        * This system method will create a basic header that will be used with
        * the output.  This method will use the heading template,
        * "heading.tpl", to generate the string that would be used for the
        * output and return it.  If not content is returned, the boolean value
        * of false will be returned.  If content is returned, the string
        * generated will be returned.  The string may be used with other system
        * methods such as add/append_module() and add/append_panel().
        *
        * @access public
        * @uses   m_arg()
        * @uses   Smarty::assign()
        * @uses   Smarty::fetch()
        * @param  string $text Heading text.
        * @return string
        */
        public function heading ( $text )
        {
            // Check argument.
            m_arg( $text, M_STRING );

            // Get global.
            global $M;

            // Assign temporary var.
            $M->TPL->assign( "admin_heading_text",
                             $text );

            // Fetch contents.
            $contents = $M->TPL->fetch( "heading.tpl" );

            // Contents not empty?
            if ( !empty( $contents ) )
            {
                // Return contents.
                return( $contents );
            }

            return( false );
        }

        /**
        * Assign Left Module Content
        *
        * This method will assign the title and content of the dedicated left
        * content module.  This method will override any previous content in
        * the dedicated left module.  This module does not repeat.
        *
        * @access public
        * @param  string  $title    Left module title.
        * @param  string  $contents Left module content.
        * @return boolean
        */
        public function module_left ( $title,
                                      $contents )
        {
            // Check arguments.
            m_arg( $title,    M_STRING );
            m_arg( $contents, M_STRING );

            // Override left module.
            $this->_left = array(

                'title'     => $title,
                'contents'  => $content,

            );

            return( true );
        }

        /**
        * Assign Right Module Content
        *
        * This method will assign the title and content of the dedicated right
        * content module.  This method will override any previous content in
        * the dedicated right module.  This module does not repeat.
        *
        * @access public
        * @param  string  $title   Right module title.
        * @param  string  $content Right module content.
        * @return boolean
        */
        public function module_right ( $title,
                                       $content )
        {
            // Check arguments.
            m_arg( $title,    M_STRING );
            m_arg( $contents, M_STRING );

            // Override right module.
            $this->_right = array(

                'title'     => $title,
                'contents'  => $content,

            );

            return( true );
        }

        /**
        * Assign Page Information
        *
        * //
        *
        * @access public
        * @uses   m_arg()
        * @uses   Smarty::assign()
        * @param  string  $title       Browser page title.
        * @param  string  $short_title Short admin page title.
        * @param  string  $long_title  Long admin page title.
        * @param  string  $type        Plugin type (system, client, or event).
        * @return boolean
        */
        public function page_info ( $title,
                                    $short_title,
                                    $long_title,
                                    $type = M_ADMIN_OTHER )
        {
            // Check vars.
            m_arg( $title,       M_STRING );
            m_arg( $short_title, M_STRING );
            m_arg( $long_title,  M_STRING );
            m_arg( $type,        M_STRING );

            // Get global.
            global $M;

            // Invalid type?
            switch ( $type )
            {
                // Valid.
                case M_ADMIN_CLIENT:
                case M_ADMIN_EVENT:
                case M_ADMIN_HOME:
                case M_ADMIN_OTHER:
                case M_ADMIN_SYSTEM:
                {
                    // Stop.
                    break;
                }

                // Invalid.
                default:
                {
                    // Report fatal error.
                    trigger_error( "Invalid plugin type specified, $type.",
                                   E_USER_ERROR );
                }
            }

            // Assign browser title.
            $M->TPL->assign( "page_title", $title );

            // Assign short page title.
            $M->TPL->assign( "short_title", $short_title );

            // Assign long page title.
            $M->TPL->assign( "long_title", $long_title );

            // Assign active link.
            $M->TPL->assign( "active_link", $type );

            return( true );
        }

        /**
        * Remove Sidebar Moduel
        *
        * //
        *
        * @access public
        * @uses   m_arg()
        * @param  integer $index Module index.
        * @return boolean
        */
        public function remove_module ( $index )
        {
            // Check argument.
            m_arg( $index, M_INTEGER );

            // Valid index?
            if ( !empty( $this->_modules[ $index ] ) )
            {
                // Remove module.
                unset( $this->_modules[ $index ] );
            }

            return( true );
        }

        /**
        * Remove Content Panel
        *
        * //
        *
        * @access public
        * @uses   m_arg()
        * @param  integer $index Panel index.
        * @return boolean
        */
        public function remove_panel ( $index )
        {
            // Check argument.
            m_arg( $index, M_INTEGER );

            // Valid index?
            if ( !empty( $this->_panels[ $index ] ) )
            {
                // Remove panel.
                unset( $this->_panels[ $index ] );
            }

            return( true );
        }

        /**
        * Render Page Contents
        *
        * //
        *
        * @access public
        * @uses   Smarty::assign()
        * @uses   Smarty::display()
        * @return void
        */
        public function render ( )
        {
            // Get global.
            global $M;

            // Assign page content.
            $M->TPL->assign ("admin_modules",
                              $this->_modules );
            $M->TPL->assign( "admin_panels",
                             $this->_panels );

            // Display index page.
            $M->TPL->display( "index.tpl" );
        }
    }

    /**
    * Admin System Plugin - Admin Class
    *
    * This system plugin admin class is the default administrative class to
    * be executed when no other admn class has been requested.  This admin
    * class a total of five pages.  The "Home" page will display any
    * statistical information returned from the listeners listening to the
    * event "admin_stats".  The "Clients" page will display a list of client
    * plugins that support admin mode and links to their administrative
    * classes.  The "Events" and "Systems" also display the same content as
    * the "Clients" page except that they display the event and system plugins
    * that support admin mode.  The "Other" page displays the system's (Mukei)
    * configuration settings and allows you to modify them.
    *
    * @package Admin_Admin
    * @version 0.2
    * @final
    */
    final class Admin_Admin
    {
        /**
        * Class Constructor
        *
        * This system method will determine what page to display by what the
        * field "page" has as its value.  If it is not a valid page name or
        * is empty, the default page of "Home" will be displayed.
        *
        * @access public
        * @uses   Admin_Admin::clients()
        * @uses   Admin_Admin::events()
        * @uses   Admin_Admin::home()
        * @uses   Admin_Admin::other()
        * @uses   Admin_Admin::systems()
        * @uses   Browser::update()
        * @return object
        */
        public function __construct ( )
        {
            // Get global.
            global $M;

            // Page empty?
            if ( empty( $M->BRW->ALL['page'] ) )
                $M->BRW->update( "page", "home" );

            // Switch on page.
            switch ( $M->BRW->ALL['page'] )
            {
                // Clients page?
                case "clients":
                {
                    // Display clients page.
                    $this->clients( );

                    break;
                }

                // Events page?
                case "events":
                {
                    // Display events page.
                    $this->events( );

                    break;
                }

                // Systems page?
                case "systems":
                {
                    // Display systems page.
                    $this->systems( );

                    break;
                }

                // Other page?
                case "other":
                {
                    // Display other page.
                    $this->other( );

                    break;
                }

                // Default to home?
                default:
                {
                    // Display home page.
                    $this->home( );
                }
            }
        }

        /**
        * Home Page
        *
        * //
        *
        * @access public
        * @uses   Admin::page_info()
        * @uses   Admin::render()
        * @return void
        */
        public function home ( )
        {
            // Get global.
            global $M;

            // Set titles.
            $M->ADM->page_info( "Home",
                                "Home",
                                "Welcome Administrator!",
                                M_ADMIN_HOME );

            // Add panel.
            $M->ADM->add_panel( "",
                                "Well it looks like this test panel works!" );

            // Render page.
            $M->ADM->render( );
        }

        /**
        * Clients Page
        *
        * //
        *
        * @access public
        * @uses   Admin::page_info()
        * @uses   Admin::render()
        * @return void
        */
        public function clients ( )
        {
            // Get global.
            global $M;

            // Set titles.
            $M->ADM->page_info( "Client Plugins",
                                "Clients",
                                "Client Plugin Administration",
                                M_ADMIN_CLIENT );

            // Render page.
            $M->ADM->render( );
        }

        /**
        * Events Page
        *
        * //
        *
        * @access public
        * @uses   Admin::page_info()
        * @uses   Admin::render()
        * @return void
        */
        public function events ( )
        {
            // Get global.
            global $M;

            // Set titles.
            $M->ADM->page_info( "Event Plugins",
                                "Events",
                                "Event Plugin Administration",
                                M_ADMIN_EVENT );

            // Render page.
            $M->ADM->render( );
        }

        /**
        * Other Page
        *
        * //
        *
        * @access public
        * @uses   Admin::page_info()
        * @uses   Admin::render()
        * @return void
        */
        public function other ( )
        {
            // Get global.
            global $M;

            // Set titles.
            $M->ADM->page_info( "Other",
                                "other",
                                "Other Administration",
                                M_ADMIN_OTHER );

            // Render page.
            $M->ADM->render( );
        }

        /**
        * Systems Page
        *
        * //
        *
        * @access public
        * @uses   Admin::page_info()
        * @uses   Admin::render()
        * @return void
        */
        public function systems ( )
        {
            // Get global.
            global $M;

            // Set titles.
            $M->ADM->page_info( "System Plugins",
                                "System",
                                "System Plugin Administration",
                                M_ADMIN_SYSTEM );

            // Render page.
            $M->ADM->render( );
        }
    }

?>